Popular Searches
Popular Course Categories
Popular Courses

Creating and using StatelessWidget

Creating and using StatelessWidget

Flutter Fundamentals

Creating and Using StatelessWidget in Flutter

StatelessWidget is one of the most important concepts in Flutter. It is used to create UI components whose configuration does not require mutable internal state. A StatelessWidget receives data through its constructor and describes the UI that should be displayed.

In Flutter, the user interface is built using widgets. StatelessWidget is especially useful for reusable UI components such as text sections, icons, buttons with fixed configuration, profile cards, headers, product cards, and other UI elements that do not need to maintain changing state.

For additional Flutter learning and training resources, visit JustAcademy Flutter Training and Register for a Course Demo.


1. What is StatelessWidget?

A StatelessWidget is a Flutter widget that does not require mutable state. Its UI is primarily determined by the values provided to the widget and the current BuildContext.

According to the Flutter API, a StatelessWidget describes part of the user interface by building other widgets. Flutter continues building the widget tree until the UI is represented by concrete rendering widgets.

Official reference: Flutter StatelessWidget API.

Basic Syntax

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return const Text('Hello Flutter');
  }
}

The build() method returns the widgets that represent the UI.


2. Why Use StatelessWidget?

StatelessWidget is useful when a UI component does not need to change its own internal data during its lifetime.

  • Creating reusable UI components
  • Displaying static content
  • Displaying data received through constructor parameters
  • Creating layouts using Row, Column, Container, Padding, and other widgets
  • Creating reusable cards and sections
  • Building headers and navigation elements
  • Creating presentation-only components
  • Keeping UI code modular and maintainable

3. Structure of a StatelessWidget

A typical StatelessWidget contains three important parts:

  1. The class extends StatelessWidget.
  2. A constructor is usually provided.
  3. The build() method returns a widget tree.
class WelcomeMessage extends StatelessWidget {
  const WelcomeMessage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Text(
      'Welcome to Flutter',
    );
  }
}

Explanation

  • extends StatelessWidget tells Flutter that the class is a stateless widget.
  • const WelcomeMessage({super.key}) defines the constructor.
  • build() describes what should appear on the screen.
  • Text() displays the message.

4. Understanding the build() Method

The build() method is responsible for describing the widget's UI.

@override
Widget build(BuildContext context) {
  return const Text('Hello World');
}

The BuildContext provides information about the widget's location in the widget tree and can be used to access inherited information such as theme, media information, localization, and navigation.

Example

class Greeting extends StatelessWidget {
  const Greeting({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Text(
        'Good Morning!',
        style: TextStyle(
          fontSize: 24,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}

5. Creating Your First StatelessWidget

Let's create a simple application using a custom StatelessWidget.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('StatelessWidget Example'),
        ),
        body: const Center(
          child: Text(
            'Hello Flutter!',
            style: TextStyle(fontSize: 24),
          ),
        ),
      ),
    );
  }
}

How It Works

  1. The main() function is the entry point.
  2. runApp() starts the Flutter application.
  3. MyApp extends StatelessWidget.
  4. The build() method returns a MaterialApp.
  5. MaterialApp contains a Scaffold.
  6. The Scaffold contains an AppBar and body.
  7. The body displays a Text widget.

6. StatelessWidget with Constructor Parameters

StatelessWidgets become more useful when they receive data through constructor parameters.

class UserCard extends StatelessWidget {
  final String name;
  final String email;

  const UserCard({
    super.key,
    required this.name,
    required this.email,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              name,
              style: const TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 8),
            Text(email),
          ],
        ),
      ),
    );
  }
}

Using the Widget

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Padding(
        padding: EdgeInsets.all(16),
        child: UserCard(
          name: 'Rahul Sharma',
          email: '[email protected]',
        ),
      ),
    );
  }
}

Here, name and email are immutable properties of the widget.


7. Why Use final Variables?

Properties of a StatelessWidget are normally declared using final.

class ProductCard extends StatelessWidget {
  final String productName;
  final double price;

  const ProductCard({
    super.key,
    required this.productName,
    required this.price,
  });

  @override
  Widget build(BuildContext context) {
    return Text('$productName - ₹$price');
  }
}

Using final makes the properties immutable after the object is created. This matches the immutable nature of widgets.


8. StatelessWidget with Container

class ColoredBoxWidget extends StatelessWidget {
  const ColoredBoxWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 200,
      height: 100,
      color: Colors.blue,
      alignment: Alignment.center,
      child: const Text(
        'Flutter',
        style: TextStyle(
          color: Colors.white,
          fontSize: 22,
        ),
      ),
    );
  }
}

This widget creates a fixed visual component containing a blue box and text.


9. StatelessWidget with Row

class UserInfo extends StatelessWidget {
  const UserInfo({super.key});

  @override
  Widget build(BuildContext context) {
    return const Row(
      children: [
        CircleAvatar(
          child: Icon(Icons.person),
        ),
        SizedBox(width: 12),
        Text(
          'John Doe',
          style: TextStyle(fontSize: 18),
        ),
      ],
    );
  }
}

This is a good example of creating a reusable horizontal UI component.


10. StatelessWidget with Column

class ProfileSection extends StatelessWidget {
  const ProfileSection({super.key});

  @override
  Widget build(BuildContext context) {
    return const Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'John Doe',
          style: TextStyle(
            fontSize: 24,
            fontWeight: FontWeight.bold,
          ),
        ),
        SizedBox(height: 8),
        Text('Flutter Developer'),
        Text('Mumbai, India'),
      ],
    );
  }
}

11. Creating a Reusable Button Widget

class CustomButton extends StatelessWidget {
  final String title;
  final VoidCallback onPressed;

  const CustomButton({
    super.key,
    required this.title,
    required this.onPressed,
  });

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(title),
    );
  }
}

Using CustomButton

CustomButton(
  title: 'Login',
  onPressed: () {
    print('Login clicked');
  },
)

The button itself is stateless, while the action to perform is provided through the callback.


12. StatelessWidget and Callbacks

A StatelessWidget can receive a callback from its parent. This allows the widget to communicate an event without storing mutable state itself.

class ActionButton extends StatelessWidget {
  final VoidCallback onTap;

  const ActionButton({
    super.key,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onTap,
      child: const Text('Click Me'),
    );
  }
}

Parent Usage

ActionButton(
  onTap: () {
    print('Button clicked');
  },
)

13. StatelessWidget and Lists

StatelessWidgets are commonly used to display list items.

class ProductItem extends StatelessWidget {
  final String name;
  final double price;

  const ProductItem({
    super.key,
    required this.name,
    required this.price,
  });

  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: const Icon(Icons.shopping_bag),
      title: Text(name),
      subtitle: Text('₹$price'),
      trailing: const Icon(Icons.arrow_forward_ios),
    );
  }
}

Example:

Column(
  children: const [
    ProductItem(
      name: 'Laptop',
      price: 55000,
    ),
    ProductItem(
      name: 'Keyboard',
      price: 1500,
    ),
    ProductItem(
      name: 'Mouse',
      price: 800,
    ),
  ],
)

14. StatelessWidget for a Profile Card

class ProfileCard extends StatelessWidget {
  final String name;
  final String role;
  final String location;

  const ProfileCard({
    super.key,
    required this.name,
    required this.role,
    required this.location,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(12),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            const CircleAvatar(
              radius: 30,
              child: Icon(Icons.person),
            ),
            const SizedBox(width: 16),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  name,
                  style: const TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(role),
                Text(location),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

15. StatelessWidget and Conditional UI

A StatelessWidget can display different UI based on constructor values. The widget itself does not change those values.

class LoginStatus extends StatelessWidget {
  final bool isLoggedIn;

  const LoginStatus({
    super.key,
    required this.isLoggedIn,
  });

  @override
  Widget build(BuildContext context) {
    return Text(
      isLoggedIn ? 'Welcome Back!' : 'Please Login',
    );
  }
}

Usage

const LoginStatus(isLoggedIn: true)

The parent can provide a different value when the widget is rebuilt.


16. StatelessWidget vs StatefulWidget

FeatureStatelessWidgetStatefulWidget
Mutable internal stateNot requiredSupported
State objectNo separate State objectUses a separate State object
UI changesBased on configuration/context and rebuildsCan change through state updates
setState()Not available directlyAvailable in State
Typical useReusable/static or configuration-driven UIInteractive or changing UI
ExampleProfile cardCounter

17. StatelessWidget Does Not Mean the Entire Screen Can Never Change

An important concept is that a StatelessWidget does not mean the screen can never change.

A StatelessWidget can rebuild when its parent provides a new configuration or when dependencies it uses change. The important point is that the widget itself does not maintain mutable internal state.

class Greeting extends StatelessWidget {
  final String name;

  const Greeting({
    super.key,
    required this.name,
  });

  @override
  Widget build(BuildContext context) {
    return Text('Hello, $name');
  }
}

If the parent rebuilds and provides a different name, the displayed text can change.


18. Using ThemeData in StatelessWidget

StatelessWidgets can access application theme information through BuildContext.

class ThemedTitle extends StatelessWidget {
  const ThemedTitle({super.key});

  @override
  Widget build(BuildContext context) {
    return Text(
      'Flutter Course',
      style: Theme.of(context).textTheme.headlineMedium,
    );
  }
}

This allows the widget to use the application's current theme instead of hard-coding every style.


19. Using MediaQuery in StatelessWidget

A StatelessWidget can also use screen information from the current context.

class ResponsiveText extends StatelessWidget {
  const ResponsiveText({super.key});

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.sizeOf(context).width;

    return Text(
      width > 600 ? 'Large Screen' : 'Small Screen',
    );
  }
}

This demonstrates that StatelessWidget can still create responsive interfaces without maintaining mutable state.


20. Using LayoutBuilder

LayoutBuilder can be used when a widget needs to adapt its layout according to the constraints supplied by its parent.

class ResponsiveBox extends StatelessWidget {
  const ResponsiveBox({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth > 600) {
          return const Text(
            'Desktop Layout',
            style: TextStyle(fontSize: 30),
          );
        }

        return const Text(
          'Mobile Layout',
          style: TextStyle(fontSize: 20),
        );
      },
    );
  }
}

21. Using const with StatelessWidget

Flutter recommends using const widgets wherever possible. A StatelessWidget can provide a const constructor when its fields can be initialized as compile-time constants.

class Welcome extends StatelessWidget {
  const Welcome({super.key});

  @override
  Widget build(BuildContext context) {
    return const Text('Welcome to Flutter');
  }
}

Then it can be created as:

const Welcome()

Using const can help Flutter avoid unnecessary widget work when the configuration is unchanged.


22. Example: Product Card

class ProductCard extends StatelessWidget {
  final String title;
  final String imageUrl;
  final double price;

  const ProductCard({
    super.key,
    required this.title,
    required this.imageUrl,
    required this.price,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Image.network(
            imageUrl,
            height: 180,
            width: double.infinity,
            fit: BoxFit.cover,
          ),
          Padding(
            padding: const EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  title,
                  style: const TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 6),
                Text(
                  '₹$price',
                  style: const TextStyle(
                    fontSize: 16,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

23. Example: Complete Stateless Flutter Application

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'StatelessWidget Demo',
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('My Flutter App'),
      ),
      body: const Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            ProfileCard(
              name: 'Amit Kumar',
              role: 'Flutter Developer',
              location: 'Delhi, India',
            ),
            SizedBox(height: 20),
            Text(
              'Welcome to Flutter Development',
              style: TextStyle(
                fontSize: 22,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class ProfileCard extends StatelessWidget {
  final String name;
  final String role;
  final String location;

  const ProfileCard({
    super.key,
    required this.name,
    required this.role,
    required this.location,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            const CircleAvatar(
              radius: 30,
              child: Icon(Icons.person),
            ),
            const SizedBox(width: 16),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  name,
                  style: const TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(role),
                Text(location),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

24. Understanding the Widget Tree

Flutter applications are constructed as a tree of widgets. A StatelessWidget can contain many child widgets.

MaterialApp
  └── Scaffold
      ├── AppBar
      │   └── Text
      └── Body
          └── Column
              ├── ProfileCard
              │   ├── CircleAvatar
              │   └── Text
              └── Text

Each widget describes a part of the user interface, and parent widgets can contain child widgets.


25. StatelessWidget and Reusable Components

One of the major advantages of StatelessWidget is component reusability.

For example, instead of writing the same product card UI multiple times, create one reusable ProductCard widget.

ProductCard(
  title: 'Laptop',
  imageUrl: 'https://example.com/laptop.jpg',
  price: 55000,
)

ProductCard(
  title: 'Mobile',
  imageUrl: 'https://example.com/mobile.jpg',
  price: 25000,
)

The same widget structure can display different information through constructor parameters.


26. Common Use Cases

  • Home page layouts
  • Profile cards
  • Product cards
  • List items
  • Headers
  • Footers
  • Static information sections
  • Reusable buttons
  • Icons and labels
  • Dashboard cards
  • Information banners
  • Empty-state screens
  • Reusable form sections
  • Presentation-only components

27. Common Mistakes

Mistake 1: Trying to Use setState()

class Example extends StatelessWidget {
  int count = 0;

  void increment() {
    setState(() {
      count++;
    });
  }
}

This is incorrect because setState() belongs to the State object of a StatefulWidget.

Correct Approach

If the widget needs to manage changing internal state, consider using StatefulWidget.

Mistake 2: Using Mutable Fields

class Example extends StatelessWidget {
  String name = 'John';
}

For a StatelessWidget, widget configuration should generally be immutable.

Prefer:

class Example extends StatelessWidget {
  final String name;

  const Example({
    super.key,
    required this.name,
  });
}

Mistake 3: Putting Too Much Logic Inside build()

The build method should primarily describe the UI. Avoid unnecessarily expensive operations inside it.

Mistake 4: Creating Reusable UI as Large Helper Methods

For reusable pieces of UI, creating a dedicated widget can improve organization and make Flutter's widget tree easier to reason about.


28. StatelessWidget Best Practices

  • Use final for widget properties.
  • Use const constructors whenever appropriate.
  • Keep widgets small and focused.
  • Use meaningful widget names.
  • Pass required data through constructors.
  • Use callbacks for user actions when appropriate.
  • Avoid unnecessary work inside build().
  • Extract reusable UI into separate widgets.
  • Keep business logic separate from presentation where appropriate.
  • Use Flutter's built-in widgets where they provide the required functionality.

29. When Should You Use StatelessWidget?

Use StatelessWidget when the component does not need to maintain mutable internal state.

Good Examples

  • A logo
  • A heading
  • A product information card
  • A profile display card
  • A static menu item
  • A reusable button configuration
  • A decorative UI component
  • A layout section

Consider StatefulWidget When

  • A value changes inside the widget.
  • The widget needs to call setState().
  • The widget manages a text editing controller.
  • The widget maintains a selected item.
  • The widget manages an animation controller.
  • The widget has temporary interactive state.
  • The UI depends on mutable state owned by that component.

30. StatelessWidget and State Management

StatelessWidget does not mean that an application cannot have state. Application state can be managed elsewhere and passed into StatelessWidgets as constructor parameters.

class CounterDisplay extends StatelessWidget {
  final int count;

  const CounterDisplay({
    super.key,
    required this.count,
  });

  @override
  Widget build(BuildContext context) {
    return Text(
      'Count: $count',
      style: const TextStyle(fontSize: 24),
    );
  }
}

A parent or state-management solution can provide the current count. The CounterDisplay widget only displays the value it receives.


31. StatelessWidget in Real-World Applications

Large Flutter applications are normally composed of many small widgets. StatelessWidgets are useful for separating the interface into reusable components.

For example, an e-commerce application might contain:

HomePage
├── HeaderWidget
├── SearchBarWidget
├── CategoryWidget
├── ProductCard
├── ProductCard
├── ProductCard
└── BottomNavigationWidget

Individual components can be implemented as StatelessWidgets when they do not own mutable state.


32. Interview Questions

Q1. What is StatelessWidget?

StatelessWidget is a Flutter widget used when the widget does not require mutable internal state.

Q2. Which method is required when creating a StatelessWidget?

The build() method is overridden to describe the widget's UI.

Q3. Can a StatelessWidget receive changing data?

Yes. It can receive new values through constructor parameters when its parent rebuilds it with a new configuration.

Q4. Can StatelessWidget use setState()?

No. setState() is provided by the State object associated with StatefulWidget.

Q5. Why are StatelessWidget properties usually final?

Widgets are immutable configuration objects, so properties are generally declared as final.

Q6. Can a StatelessWidget use callbacks?

Yes. A callback can be passed through the constructor to handle events such as button presses.

Q7. What is the purpose of BuildContext?

BuildContext identifies the widget's location in the widget tree and provides access to information available from its surrounding widget hierarchy.

Q8. Why use const with StatelessWidget?

A const widget can be created as a compile-time constant when its configuration allows it, helping Flutter reduce unnecessary work during rebuilds.


33. Practice Exercise

Create a reusable StudentCard StatelessWidget with the following properties:

  • Student name
  • Course name
  • Email
  • Phone number
  • Profile icon

Requirements:

  1. Create a separate StatelessWidget called StudentCard.
  2. Use constructor parameters.
  3. Declare the properties as final.
  4. Use a Card widget.
  5. Use Row and Column.
  6. Add a CircleAvatar.
  7. Display all student information.
  8. Use a const constructor where possible.

Starter Code

class StudentCard extends StatelessWidget {
  final String name;
  final String course;
  final String email;
  final String phone;

  const StudentCard({
    super.key,
    required this.name,
    required this.course,
    required this.email,
    required this.phone,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            const CircleAvatar(
              child: Icon(Icons.person),
            ),
            const SizedBox(width: 16),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(name),
                Text(course),
                Text(email),
                Text(phone),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

34. Quick Revision

ConceptMeaning
StatelessWidgetWidget that does not require mutable internal state
build()Method used to describe the UI
BuildContextRepresents the widget's location in the widget tree
finalUsed for immutable widget properties
constUsed for compile-time constant widget configurations when possible
ConstructorUsed to receive configuration/data
CallbackUsed to pass actions/events into a widget
StatefulWidgetUsed when mutable state needs to be managed by a widget

35. Key Takeaways

  • StatelessWidget is used for UI that does not require mutable internal state.
  • The build() method describes the widget's UI.
  • Constructor parameters are commonly used to provide data to a StatelessWidget.
  • Widget properties are generally immutable and declared using final.
  • StatelessWidgets can contain other widgets and form a widget tree.
  • StatelessWidgets can receive callbacks for handling events.
  • StatelessWidgets can use BuildContext to access inherited information such as theme and layout information.
  • Use const constructors and widgets where appropriate.
  • Reusable StatelessWidgets help create clean and maintainable Flutter applications.
  • When a component needs to own mutable state, StatefulWidget may be more appropriate.

36. Learning Resources


Conclusion

StatelessWidget is a fundamental building block of Flutter applications. It is ideal for reusable UI components whose own configuration does not require mutable internal state. By combining constructor parameters, immutable properties, the build() method, callbacks, and other Flutter widgets, developers can create clean, reusable, and maintainable interfaces.

Understanding StatelessWidget is also an important foundation for learning StatefulWidget, widget trees, state management, responsive UI, and larger Flutter application architecture.

For structured Flutter learning, explore JustAcademy Flutter Training and book a course demo.

whatsapp